import areaposition


def identify_sequences(tile_count):
    """
    严格识别顺子（每张牌最多参与1个顺子）
    :param tile_count: 牌频字典 {牌: 数量}
    :return: 所有合法且不重复的顺子（合并为单张牌的集合）
    """
    used = {}  # 记录每张牌已使用的次数（初始为0）
    for tile in tile_count:
        used[tile] = 0

    sequences = set()  # 最终的顺子牌集合

    # 按花色处理（万1-9、筒10-18、条19-27）
    for suit_start in [1, 10, 19]:
        suit_end = suit_start + 8  # 花色结束编号（9、18、27）
        # 遍历该花色下所有可能的顺子起点x
        for x in range(suit_start, suit_end - 1):
            # 检查x、x+1、x+2是否存在，且未被用尽（剩余数量 >= 1）
            if (tile_count.get(x, 0) - used[x] >= 1 and
                    tile_count.get(x + 1, 0) - used[x + 1] >= 1 and
                    tile_count.get(x + 2, 0) - used[x + 2] >= 1):
                # 标记这3张牌各使用1次
                used[x] += 1
                used[x + 1] += 1
                used[x + 2] += 1
                # 将这3张牌加入顺子集合
                sequences.update([x, x + 1, x + 2])

    return sequences


def get_hand_from_global():
    """从全局card_position数组中提取14张有效手牌（牌01到牌13 + 新牌）"""
    hand = []
    # 提取牌01到牌13（索引1到13）
    for i in range(1, 14):
        card_value = areaposition.card_position[i].name
        # 确保name是整数（若实际存储为字符串则转换）
        hand.append(int(card_value) if isinstance(card_value, str) else card_value)
    # 提取新牌（索引14）
    new_card = areaposition.card_position[14].name
    hand.append(int(new_card) if isinstance(new_card, str) else new_card)
    return hand


def calculate_discard():
    """从全局card_position读取手牌并决策舍牌"""
    hand = get_hand_from_global()
    return decide_discard_with_efficiency(hand)


def count_waits(hand):
    """计算当前手牌的有效进张数（能减少向听数的牌总数）"""
    # 复制手牌并去重，避免重复计算
    unique_tiles = set(hand)
    # 所有可能的牌（1-34）
    all_tiles = set(range(1, 35))
    # 统计当前手牌的牌频
    tile_count = {}
    for t in hand:
        tile_count[t] = tile_count.get(t, 0) + 1

    waits = 0  # 有效进张数

    for tile in all_tiles:
        # 该牌已达4张（不可能再摸到），跳过
        if tile_count.get(tile, 0) >= 4:
            continue

        # 模拟摸到该牌后的手牌（14+1=15张，需舍1张才能听牌，但此处仅计算进张有效性）
        temp_count = tile_count.copy()
        temp_count[tile] = temp_count.get(tile, 0) + 1

        # 判断该进张是否能形成有效搭子（刻子、对子、顺子搭子）
        # 1. 刻子搭子（已有2张，进1张成刻子）
        if temp_count[tile] == 3:
            waits += 1
            continue

        # 2. 对子搭子（已有1张，进1张成对子）
        if temp_count[tile] == 2:
            waits += 1
            continue

        # 3. 顺子搭子（数牌适用，检查相邻牌是否能形成12/23/78/89等搭子）
        if 1 <= tile <= 27:  # 仅万筒条
            suit = (tile - 1) // 9  # 0=万，1=筒，2=条
            # 检查是否有tile-1或tile+1（形成边搭或坎搭）
            left = tile - 1
            right = tile + 1
            if (left >= 1 and (left - 1) // 9 == suit and temp_count.get(left, 0) >= 1) or \
                    (right <= 27 and (right - 1) // 9 == suit and temp_count.get(right, 0) >= 1):
                waits += 1

    return waits


def decide_discard_with_efficiency(hand):
    """结合牌效计算的舍牌决策"""
    # 牌型定义（修正后）
    # 万1-9，筒10-18，条19-27，东28，南29，西30，北31，白32，发33，中34

    # 1. 统计牌频
    tile_count = {}
    for tile in hand:
        tile_count[tile] = tile_count.get(tile, 0) + 1

    # 2. 识别刻子、对子、顺子
    triplets = {t for t, cnt in tile_count.items() if cnt >= 3}

    pairs = {t for t, cnt in tile_count.items() if cnt == 2}
    sorted_hand = sorted(hand)
    sequences = set()
    for i in range(len(sorted_hand) - 2):
        a, b, c = sorted_hand[i], sorted_hand[i+1], sorted_hand[i+2]
        if 1 <= a < b < c <= 27 and (a-1)//9 == (b-1)//9 == (c-1)//9 and b == a+1 and c == b+1:
            sequences.update([a, b, c])
    # # 修正：识别顺子
    # valid_sequences = identify_sequences(tile_count)
    # # 将所有顺子中的牌合并到sequences集合（用于后续判断“是否属于有效组合”）
    # sequences = set()
    # for seq in valid_sequences:
    #     sequences.update(seq)

    def is_in_valid_combination(tile):
        return tile in triplets or tile in sequences or tile in pairs

    # 3. 按优先级筛选候选舍牌
    candidates = []

    # 优先级1：南、西、北（29,30,31）
    for wind in [29, 30, 31]:
        if wind in tile_count and tile_count[wind] < 3:
            candidates.append(wind)
            return wind

    # 有四张舍去一张
    for tile in hand:
        if tile_count[tile] >= 4:
            return tile
    # if candidates:
    #     # 计算候选牌的牌效（舍牌后手牌的进张数），选进张最少的
    #     min_waits = float('inf')
    #     best_tile = candidates[0]
    #     for t in candidates:
    #         # 模拟舍牌后的手牌
    #         new_hand = [x for x in hand if x != t][:13]  # 舍牌后保留13张
    #         waits = count_waits(new_hand)
    #         if waits < min_waits:
    #             min_waits = waits
    #             best_tile = t

    # 优先级2：单张东、白、发、中（28,32,33,34）
    for honor in [28, 32, 33, 34]:
        if tile_count.get(honor, 0) == 1 and not is_in_valid_combination(honor):
            candidates.append(honor)
    if candidates:
        min_waits = float('inf')
        best_tile = candidates[0]
        for t in candidates:
            new_hand = [x for x in hand if x != t][:13]
            waits = count_waits(new_hand)
            if waits < min_waits:
                min_waits = waits
                best_tile = t
        return best_tile

    # 优先级3：单张幺九（无法形成搭子）
    yaochu = [1, 9, 10, 18, 19, 27]
    for yao in yaochu:
        if tile_count.get(yao, 0) == 1 and not is_in_valid_combination(yao):
            has_adjacent = False
            if yao == 1:
                has_adjacent = 2 in tile_count or 3 in tile_count
            elif yao == 9:
                has_adjacent = 7 in tile_count or 8 in tile_count
            elif yao == 10:
                has_adjacent = 11 in tile_count or 12 in tile_count
            elif yao == 18:
                has_adjacent = 16 in tile_count or 17 in tile_count
            elif yao == 19:
                has_adjacent = 20 in tile_count or 21 in tile_count
            elif yao == 27:
                has_adjacent = 25 in tile_count or 26 in tile_count
            if not has_adjacent:
                candidates.append(yao)
    if candidates:
        min_waits = float('inf')
        best_tile = candidates[0]
        for t in candidates:
            new_hand = [x for x in hand if x != t][:13]
            waits = count_waits(new_hand)
            if waits < min_waits:
                min_waits = waits
                best_tile = t
        return best_tile

    # 优先级4：非幺九单张废牌
    middle_tiles = []
    edge_tiles = []
    for tile in tile_count:
        if 1 <= tile <= 27:
            if tile_count[tile] == 1 and not is_in_valid_combination(tile):
                base = (tile - 1) % 9 + 1
                if base in [2, 3, 4, 5, 6, 7, 8]:
                    middle_tiles.append(tile)
                else:
                    edge_tiles.append(tile)
    # 优先丢边
    candidates = edge_tiles + middle_tiles
    if candidates:
        min_waits = float('inf')
        best_tile = candidates[0]
        for t in candidates:
            new_hand = [x for x in hand if x != t][:13]
            waits = count_waits(new_hand)
            if waits < min_waits:
                min_waits = waits
                best_tile = t
        return best_tile

    # 优先级5：拆多余对子或弱搭子（按牌效）
    extra_pairs = [t for t in pairs if t not in triplets]
    if len(extra_pairs) > 1:
        candidates = extra_pairs
    else:
        min_cnt = min(tile_count.values())
        candidates = [t for t, cnt in tile_count.items() if cnt == min_cnt]

    # 最终按牌效筛选
    min_waits = float('inf')
    best_tile = candidates[0]
    for t in candidates:
        new_hand = [x for x in hand if x != t][:13]
        waits = count_waits(new_hand)
        if waits < min_waits:
            min_waits = waits
            best_tile = t
    return best_tile


# def calculate_discard():
#     nums = [pos.name for pos in areaposition.card_position]
#     """
#     计算日麻手牌中最优丢弃牌
#     参数: nums[15] - 前14位为手牌(1-13已排序，14为新摸牌)，第15位预留(无实际作用)
#     返回: 最优丢弃牌的数字(1-34)
#     """
#     from collections import defaultdict
#
#     # 常量定义
#     MAN = list(range(1, 10))  # 万子1-9
#     PIN = list(range(10, 19))  # 筒子10-18
#     SOU = list(range(19, 28))  # 条子19-27
#     WIND = list(range(28, 32))  # 风牌28-31(东南西北)
#     DRAGON = list(range(32, 35))  # 字牌32-34(白、发、中)
#     ALL_TILES = list(range(1, 35))
#
#     def count_tiles(tiles):
#         """统计手牌中每张牌的数量"""
#         count = defaultdict(int)
#         for t in tiles:
#             count[t] += 1
#         return count
#
#     def is_terminal(tile):
#         """判断是否为幺九牌"""
#         if tile in MAN:
#             return tile in [1, 9]
#         elif tile in PIN:
#             return tile in [10, 18]
#         elif tile in SOU:
#             return tile in [19, 27]
#         return True  # 风牌和字牌都算幺九
#
#     def calculate_shanten(tiles):
#         """计算向听数(0为听牌，数值越小越好)"""
#         count = count_tiles(tiles)
#         min_shanten = float('inf')
#
#         # 枚举所有可能的雀头(对子)
#         possible_heads = [t for t in count if count[t] >= 2]
#         possible_heads.append(None)  # 也考虑没有雀头的情况(需额外找对子)
#
#         for head in possible_heads:
#             temp_count = count.copy()
#             needed = 0  # 需要补充的牌数
#
#             # 扣除雀头的2张牌
#             if head is not None:
#                 temp_count[head] -= 2
#                 if temp_count[head] < 0:
#                     continue
#
#             # 计算面子(刻子/顺子)所需补充的牌数
#             for suit in [MAN, PIN, SOU]:  # 处理数牌
#                 suit_tiles = [t for t in suit if temp_count[t] > 0]
#                 if not suit_tiles:
#                     continue
#
#                 # 按数字排序处理顺子
#                 sorted_tiles = sorted(suit_tiles)
#                 i = 0
#                 while i < len(sorted_tiles):
#                     t = sorted_tiles[i]
#                     # 尝试组成顺子
#                     if t + 1 in temp_count and t + 2 in temp_count:
#                         # 计算可组成的顺子数量
#                         max_straight = min(
#                             temp_count[t],
#                             temp_count[t + 1],
#                             temp_count[t + 2]
#                         )
#                         temp_count[t] -= max_straight
#                         temp_count[t + 1] -= max_straight
#                         temp_count[t + 2] -= max_straight
#                     # 处理剩余的刻子
#                     if temp_count[t] > 0:
#                         needed += temp_count[t] % 3  # 每3张组成1个刻子，余数需要补充
#                     i += 1
#
#             # 处理字牌(只能组成刻子)
#             for t in WIND + DRAGON:
#                 if temp_count[t] > 0:
#                     needed += temp_count[t] % 3
#
#             # 计算当前雀头下的向听数
#             current_shanten = needed
#             if head is None:
#                 current_shanten += 1  # 没有雀头需要额外找1个对子
#
#             if current_shanten < min_shanten:
#                 min_shanten = current_shanten
#
#         return min_shanten if min_shanten != float('inf') else 6  # 最大向听数默认6
#
#     def get_effective_draws(tiles):
#         """计算有效进张数(能减少向听数的牌)"""
#         original_shanten = calculate_shanten(tiles)
#         effective = 0
#
#         for tile in ALL_TILES:
#             # 模拟摸到该牌后的手牌
#             new_tiles = tiles + [tile]
#             new_shanten = calculate_shanten(new_tiles)
#             if new_shanten == original_shanten - 1:
#                 effective += 1
#
#         return effective
#
#     # 主逻辑：评估每张牌的丢弃价值
#     hand = nums[1:15]  # 取前14张手牌
#     evaluation = []
#
#     for i in range(14):
#         # 模拟丢弃第i张牌
#         discarded_tile = hand[i]
#         remaining = hand[:i] + hand[i + 1:]
#
#         #  计算丢弃后的向听数和有效进张
#         shanten = calculate_shanten(remaining)
#         effective = get_effective_draws(remaining)
#
#         # 计算价值分(综合评分，越低越该丢弃)
#         # 向听数权重更高(3倍)，其次是有效进张数，最后考虑幺九牌惩罚
#         value_score = shanten * 3 - effective
#         if is_terminal(discarded_tile):
#             value_score -= 0.5  # 幺九牌略优先丢弃
#
#         evaluation.append((discarded_tile, shanten, effective, value_score))
#
#     # 排序决策：优先价值分低的，相同则选出现次数多的
#     evaluation.sort(key=lambda x: (x[3], -hand.count(x[0])))
#
#     return evaluation[0][0]


# 测试示例
if __name__ == "__main__":
    # 示例手牌：1万*2、2万、3万、5筒、6筒、8筒、9筒、1条、2条、4条、5条*2、白发
    test_hand = [1, 1, 3, 4, 5, 14, 15, 16, 17, 18, 22, 23, 23, 1, 0]  # 第15位无意义
    print(f"最优丢弃牌: {calculate_discard(test_hand)}")  # 预期输出32(白发)
